package com.chuangke.sinotrukbudget.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chuangke.admin.data.builder.DeptDataBuilder;
import com.chuangke.admin.dto.DataPermissionRequest;
import com.chuangke.admin.model.SysDataPermission;
import com.chuangke.admin.model.SysDept;
import com.chuangke.admin.service.SysDataPermissionService;
import com.chuangke.admin.service.SysDeptService;
import com.chuangke.common.utils.StringUtils;
import com.chuangke.core.data.builder.DataBuildConfig;
import com.chuangke.core.data.builder.DataBuilder;
import com.chuangke.core.exception.ChuangkeException;
import com.chuangke.core.id.IdManager;
import com.chuangke.core.page.CkPageQuery;
import com.chuangke.core.page.PageUtil;
import com.chuangke.sinotrukbudget.data.builder.BudgetAccountBuilder;
import com.chuangke.sinotrukbudget.model.BudgetAccount;
import com.chuangke.sinotrukbudget.model.BudgetAuditControl;
import com.chuangke.sinotrukbudget.sdao.BudgetAuditControlDaoService;
import com.chuangke.sinotrukbudget.service.BudgetAccountService;
import com.chuangke.sinotrukbudget.service.BudgetAuditControlService;

@Service
public class BudgetAuditControlServiceImpl implements BudgetAuditControlService {

	public static final String CACHE_NAME = "budget_audit_control";

	@Autowired
	private BudgetAuditControlDaoService budgetAuditControlDaoService;

	@Autowired
	private SysDataPermissionService sysDataPermissionService;

	@Autowired
	private SysDeptService sysDeptService;

	@Autowired
	private BudgetAccountService budgetAccountService;

	@Override
	public void save(BudgetAuditControl record) {
		((BudgetAuditControlService) AopContext.currentProxy()).save(Arrays.asList(record));
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	public void save(List<BudgetAuditControl> records) {
		if (CollectionUtils.isEmpty(records)) {
			return;
		}

		records.forEach(record -> record.setId(IdManager.nextId()));
		
		QueryWrapper<BudgetAuditControl> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(BudgetAuditControl::getDeptId, records.get(0).getDeptId()).eq(BudgetAuditControl::getControlType, records.get(0).getControlType()) ;
		List<BudgetAuditControl> list = budgetAuditControlDaoService.list(queryWrapper) ;
		list.addAll(records) ;
		List<String> controlModeList = list.stream().map(BudgetAuditControl::getControlMode).distinct()
				.collect(Collectors.toList());
		if (!CollectionUtils.isEmpty(controlModeList) && controlModeList.size() > 1) {
			throw new ChuangkeException("只能维护一种控制方式");
		}

		budgetAuditControlDaoService.saveOrUpdateBatch(records);
	}

	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void delete(BudgetAuditControl record) {
		budgetAuditControlDaoService.removeById(record);
	}

	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void delete(List<BudgetAuditControl> records) {
		List<String> idList = records.stream().map(BudgetAuditControl::getId).collect(Collectors.toList());
		budgetAuditControlDaoService.removeBatchByIds(idList);
	}
	
	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void deleteByIds(List<String> ids) {
		budgetAuditControlDaoService.removeByIds(ids) ;
	}

	@Cacheable(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public Map<String, BudgetAuditControl> findMap() {
		List<BudgetAuditControl> list = budgetAuditControlDaoService.list();
		return list.stream().collect(Collectors.toMap(BudgetAuditControl::getId, a -> a));
	}

	@Override
	public BudgetAuditControl findById(String id) {
		if (id == null) {
			return null;
		}

		Map<String, BudgetAuditControl> map = ((BudgetAuditControlService) AopContext.currentProxy()).findMap();
		return map.get(id);
	}

	@Override
	public IPage<BudgetAuditControl> page(CkPageQuery page) {
		String controlType = (String)page.get("controlType") ; 
		List<BudgetAuditControl> allList = ((BudgetAuditControlService) AopContext.currentProxy()).findList(controlType);

		String name = (String)page.get( "name");
		String deptId = (String)page.get( "deptId");
		
		if(!StrUtil.isBlank(name)) {
			allList = allList.stream().filter( bac -> bac.getControlObject().contains(name) || bac.getControlObjectName().contains(name)).collect(Collectors.toList());
		}
		if(!StrUtil.isBlank(deptId)) {
			allList = allList.stream().filter( bac -> bac.getDeptId().contains(deptId)).collect(Collectors.toList());
		}
		
		return PageUtil.findPage(page, allList);
	}

	@Override
	public List<String> getBudgetAuditControlByUser(String userId, String controlType) {
		DataPermissionRequest dpr = new DataPermissionRequest();
		dpr.setType(SysDataPermission.TYPE_USER_DUTY);
		dpr.setMaster1Id(userId);
		List<SysDataPermission> sdpList = sysDataPermissionService.find(dpr);

		if (CollectionUtils.isEmpty(sdpList)) {
			return new ArrayList<>();
		}

		List<String> deptIdList = sdpList.stream().map(SysDataPermission::getDataId).collect(Collectors.toList());
		Map<String, BudgetAuditControl> map = ((BudgetAuditControlService) AopContext.currentProxy()).findMap();

		List<BudgetAuditControl> bacList = map.values().stream()
				.filter(bac -> controlType.equals(bac.getControlType()) && deptIdList.contains(bac.getDeptId()))
				.collect(Collectors.toList());

		if (CollectionUtils.isEmpty(bacList)) {
			return new ArrayList<>();
		}

		Map<String, List<BudgetAuditControl>> controlMap = bacList.stream()
				.collect(Collectors.groupingBy(BudgetAuditControl::getDeptId));

		List<String> controlObjectList = new ArrayList<>();

		for (List<BudgetAuditControl> list : controlMap.values()) {
			List<String> coList = list.stream().map(BudgetAuditControl::getControlObject).collect(Collectors.toList());
			BudgetAuditControl bac = list.get(0);
			if (BudgetAuditControl.CONTROL_MODE_BH.equals(bac.getControlMode())) {
				controlObjectList.addAll(coList);
			} else {
				if (BudgetAuditControl.CONTROL_TYPE_DEPT.equals(controlType)) {
					List<String> deptIdAllList = sysDeptService.findMap().values().stream()
							.filter(dept -> dept.getId().endsWith("INP")).map(SysDept::getId)
							.collect(Collectors.toList());
					deptIdAllList.removeAll(coList);
					controlObjectList.addAll(deptIdAllList);
				} else {
					List<String> accountIdList = budgetAccountService.findLastLevel().stream().map(BudgetAccount::getId)
							.collect(Collectors.toList());
					accountIdList.removeAll(coList);
					controlObjectList.addAll(accountIdList);
				}
			}
		}

		return controlObjectList;
	}

	@Override
	public List<BudgetAuditControl> findList() {
		Map<String, BudgetAuditControl> map = ((BudgetAuditControlService) AopContext.currentProxy()).findMap();
		Map<String,List<BudgetAuditControl>> groupMap = map.values().stream().collect(Collectors.groupingBy(BudgetAuditControl::getControlType));
		
		List<BudgetAuditControl> deptList = groupMap.get(BudgetAuditControl.CONTROL_TYPE_DEPT) ;
		if(!CollectionUtils.isEmpty(deptList)) {
			DataBuilder.of(deptList)
			.appendBuilder(new DeptDataBuilder(), new DataBuildConfig("controlObject", "controlObjectName")).build();
		}
		
		List<BudgetAuditControl> accountList = groupMap.get(BudgetAuditControl.CONTROL_TYPE_ACCOUNT) ;
		if(!CollectionUtils.isEmpty(accountList)) {
			DataBuilder.of(accountList)
			.appendBuilder(new BudgetAccountBuilder(), new DataBuildConfig("controlObject", "controlObjectName")).build();
		}
		
		return new ArrayList<>(map.values());
	}
	
	@Override
	public List<BudgetAuditControl> findList(String controlType) {
		List<BudgetAuditControl> allList = ((BudgetAuditControlService) AopContext.currentProxy()).findList();
		Map<String,List<BudgetAuditControl>> groupMap = allList.stream().collect(Collectors.groupingBy(BudgetAuditControl::getControlType));
		return groupMap.get(controlType) ;
	}

}
